home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / lpr / lpr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-16  |  14.2 KB  |  690 lines

  1. /*
  2.  * Copyright (c) 1983 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that this notice is preserved and that due credit is given
  7.  * to the University of California at Berkeley. The name of the University
  8.  * may not be used to endorse or promote products derived from this
  9.  * software without specific prior written permission. This software
  10.  * is provided ``as is'' without express or implied warranty.
  11.  */
  12.  
  13. #ifndef lint
  14. char copyright[] =
  15. "@(#) Copyright (c) 1983 Regents of the University of California.\n\
  16.  All rights reserved.\n";
  17. #endif /* not lint */
  18.  
  19. #ifndef lint
  20. static char sccsid[] = "@(#)lpr.c    5.3 (Berkeley) 5/5/88";
  21. #endif /* not lint */
  22.  
  23. /*
  24.  *      lpr -- off line print
  25.  *
  26.  * Allows multiple printers and printers on remote machines by
  27.  * using information from a printer data base.
  28.  */
  29.  
  30. #include <stdio.h>
  31. #include <sys/types.h>
  32. #include <sys/file.h>
  33. #include <sys/stat.h>
  34. #include <pwd.h>
  35. #include <grp.h>
  36. #include <signal.h>
  37. #include <ctype.h>
  38. #include <syslog.h>
  39. #include "lp.local.h"
  40.  
  41. char    *tfname;        /* tmp copy of cf before linking */
  42. char    *cfname;        /* daemon control files, linked from tf's */
  43. char    *dfname;        /* data files */
  44.  
  45. int    nact;            /* number of jobs to act on */
  46. int    tfd;            /* control file descriptor */
  47. int     mailflg;        /* send mail */
  48. int    qflag;            /* q job, but don't exec daemon */
  49. char    format = 'f';        /* format char for printing files */
  50. int    rflag;            /* remove files upon completion */    
  51. int    sflag;            /* symbolic link flag */
  52. int    inchar;            /* location to increment char in file names */
  53. int     ncopies = 1;        /* # of copies to make */
  54. int    iflag;            /* indentation wanted */
  55. int    indent;            /* amount to indent */
  56. int    hdr = 1;        /* print header or not (default is yes) */
  57. int     userid;            /* user id */
  58. char    *person;        /* user name */
  59. char    *title;            /* pr'ing title */
  60. char    *fonts[4];        /* troff font names */
  61. char    *width;            /* width for versatec printing */
  62. char    host[32];        /* host name */
  63. char    *class = host;        /* class title on header page */
  64. char    *jobname;        /* job name on header page */
  65. char    *name;            /* program name */
  66. char    *printer;        /* printer name */
  67. struct    stat statb;
  68.  
  69. int    MX;            /* maximum number of blocks to copy */
  70. int    MC;            /* maximum number of copies allowed */
  71. int    DU;            /* daemon user-id */
  72. char    *SD;            /* spool directory */
  73. char    *LO;            /* lock file name */
  74. char    *RG;            /* restrict group */
  75. short    SC;            /* suppress multiple copies */
  76.  
  77. char    *getenv();
  78. char    *rindex();
  79. char    *linked();
  80. int    cleanup();
  81.  
  82. /*ARGSUSED*/
  83. main(argc, argv)
  84.     int argc;
  85.     char *argv[];
  86. {
  87.     extern struct passwd *getpwuid();
  88.     struct passwd *pw;
  89.     struct group *gptr;
  90.     extern char *itoa();
  91.     register char *arg, *cp;
  92.     char buf[BUFSIZ];
  93.     int i, f;
  94.     struct stat stb;
  95.  
  96.     if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
  97.         signal(SIGHUP, cleanup);
  98.     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  99.         signal(SIGINT, cleanup);
  100.     if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
  101.         signal(SIGQUIT, cleanup);
  102.     if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
  103.         signal(SIGTERM, cleanup);
  104.  
  105.     name = argv[0];
  106. #ifndef sprite
  107.     gethostname(host, sizeof (host));
  108. #else
  109.     strcpy(host,"sprite.Berkeley.EDU");
  110. #endif
  111.     openlog("lpd", 0, LOG_LPR);
  112.  
  113.     while (argc > 1 && argv[1][0] == '-') {
  114.         argc--;
  115.         arg = *++argv;
  116.         switch (arg[1]) {
  117.  
  118.         case 'P':        /* specifiy printer name */
  119.             if (arg[2])
  120.                 printer = &arg[2];
  121.             else if (argc > 1) {
  122.                 argc--;
  123.                 printer = *++argv;
  124.             }
  125.             break;
  126.  
  127.         case 'C':        /* classification spec */
  128.             hdr++;
  129.             if (arg[2])
  130.                 class = &arg[2];
  131.             else if (argc > 1) {
  132.                 argc--;
  133.                 class = *++argv;
  134.             }
  135.             break;
  136.  
  137.         case 'J':        /* job name */
  138.             hdr++;
  139.             if (arg[2])
  140.                 jobname = &arg[2];
  141.             else if (argc > 1) {
  142.                 argc--;
  143.                 jobname = *++argv;
  144.             }
  145.             break;
  146.  
  147.         case 'T':        /* pr's title line */
  148.             if (arg[2])
  149.                 title = &arg[2];
  150.             else if (argc > 1) {
  151.                 argc--;
  152.                 title = *++argv;
  153.             }
  154.             break;
  155.  
  156.         case 'l':        /* literal output */
  157.         case 'p':        /* print using ``pr'' */
  158.         case 't':        /* print troff output (cat files) */
  159.         case 'n':        /* print ditroff output */
  160.         case 'd':        /* print tex output (dvi files) */
  161.         case 'g':        /* print graph(1G) output */
  162.         case 'c':        /* print cifplot output */
  163.         case 'v':        /* print vplot output */
  164.             format = arg[1];
  165.             break;
  166.  
  167.         case 'f':        /* print fortran output */
  168.             format = 'r';
  169.             break;
  170.  
  171.         case '4':        /* troff fonts */
  172.         case '3':
  173.         case '2':
  174.         case '1':
  175.             if (argc > 1) {
  176.                 argc--;
  177.                 fonts[arg[1] - '1'] = *++argv;
  178.             }
  179.             break;
  180.  
  181.         case 'w':        /* versatec page width */
  182.             width = arg+2;
  183.             break;
  184.  
  185.         case 'r':        /* remove file when done */
  186.             rflag++;
  187.             break;
  188.  
  189.         case 'm':        /* send mail when done */
  190.             mailflg++;
  191.             break;
  192.  
  193.         case 'h':        /* toggle want of header page */
  194.             hdr = !hdr;
  195.             break;
  196.  
  197.         case 's':        /* try to link files */
  198.             sflag++;
  199.             break;
  200.  
  201.         case 'q':        /* just q job */
  202.             qflag++;
  203.             break;
  204.  
  205.         case 'i':        /* indent output */
  206.             iflag++;
  207.             indent = arg[2] ? atoi(&arg[2]) : 8;
  208.             break;
  209.  
  210.         case '#':        /* n copies */
  211.             if (isdigit(arg[2])) {
  212.                 i = atoi(&arg[2]);
  213.                 if (i > 0)
  214.                     ncopies = i;
  215.             }
  216.         }
  217.     }
  218.     if (printer == NULL && (printer = getenv("PRINTER")) == NULL)
  219.         printer = DEFLP;
  220.     chkprinter(printer);
  221.     if (SC && ncopies > 1)
  222.         fatal("multiple copies are not allowed");
  223.     if (MC > 0 && ncopies > MC)
  224.         fatal("only %d copies are allowed", MC);
  225.     /*
  226.      * Get the identity of the person doing the lpr using the same
  227.      * algorithm as lprm. 
  228.      */
  229.     userid = getuid();
  230.     if ((pw = getpwuid(userid)) == NULL)
  231.         fatal("Who are you?");
  232.     person = pw->pw_name;
  233.     /*
  234.      * Check for restricted group access.
  235.      */
  236.     if (RG != NULL) {
  237.         if ((gptr = getgrnam(RG)) == NULL)
  238.             fatal("Restricted group specified incorrectly");
  239.         if (gptr->gr_gid != getgid()) {
  240.             while (*gptr->gr_mem != NULL) {
  241.                 if ((strcmp(person, *gptr->gr_mem)) == 0)
  242.                     break;
  243.                 gptr->gr_mem++;
  244.             }
  245.             if (*gptr->gr_mem == NULL)
  246.                 fatal("Not a member of the restricted group");
  247.         }
  248.     }
  249.     /*
  250.      * Check to make sure queuing is enabled if userid is not root.
  251.      */
  252.     (void) sprintf(buf, "%s/%s", SD, LO);
  253.     if (userid && stat(buf, &stb) == 0 && (stb.st_mode & 010))
  254.         fatal("Printer queue is disabled");
  255.     /*
  256.      * Initialize the control file.
  257.      */
  258.     mktemps();
  259.     tfd = nfile(tfname);
  260.     (void) fchown(tfd, DU, -1);    /* owned by daemon for protection */
  261.     card('H', host);
  262.     card('P', person);
  263.     if (hdr) {
  264.         if (jobname == NULL) {
  265.             if (argc == 1)
  266.                 jobname = "stdin";
  267.             else
  268.                 jobname = (arg = rindex(argv[1], '/')) ? arg+1 : argv[1];
  269.         }
  270.         card('J', jobname);
  271.         card('C', class);
  272.         card('L', person);
  273.     }
  274.     if (iflag)
  275.         card('I', itoa(indent));
  276.     if (mailflg)
  277.         card('M', person);
  278.     if (format == 't' || format == 'n' || format == 'd')
  279.         for (i = 0; i < 4; i++)
  280.             if (fonts[i] != NULL)
  281.                 card('1'+i, fonts[i]);
  282.     if (width != NULL)
  283.         card('W', width);
  284.  
  285.     /*
  286.      * Read the files and spool them.
  287.      */
  288.     if (argc == 1)
  289.         copy(0, " ");
  290.     else while (--argc) {
  291.         if ((f = test(arg = *++argv)) < 0)
  292.             continue;    /* file unreasonable */
  293.  
  294.         if (sflag && (cp = linked(arg)) != NULL) {
  295.             (void) sprintf(buf, "%d %d", statb.st_dev, statb.st_ino);
  296.             card('S', buf);
  297.             if (format == 'p')
  298.                 card('T', title ? title : arg);
  299.             for (i = 0; i < ncopies; i++)
  300.                 card(format, &dfname[inchar-2]);
  301.             card('U', &dfname[inchar-2]);
  302.             if (f)
  303.                 card('U', cp);
  304.             card('N', arg);
  305.             dfname[inchar]++;
  306.             nact++;
  307.             continue;
  308.         }
  309.         if (sflag)
  310.             printf("%s: %s: not linked, copying instead\n", name, arg);
  311.         if ((i = open(arg, O_RDONLY)) < 0) {
  312.             printf("%s: cannot open %s\n", name, arg);
  313.             continue;
  314.         }
  315.         copy(i, arg);
  316.         (void) close(i);
  317.         if (f && unlink(arg) < 0)
  318.             printf("%s: %s: not removed\n", name, arg);
  319.     }
  320.  
  321.     if (nact) {
  322.         (void) close(tfd);
  323.         tfname[inchar]--;
  324.         /*
  325.          * Touch the control file to fix position in the queue.
  326.          */
  327.         if ((tfd = open(tfname, O_RDWR)) >= 0) {
  328.             char c;
  329.  
  330.             if (read(tfd, &c, 1) == 1 && lseek(tfd, 0L, 0) == 0 &&
  331.                 write(tfd, &c, 1) != 1) {
  332.                 printf("%s: cannot touch %s\n", name, tfname);
  333.                 tfname[inchar]++;
  334.                 cleanup();
  335.             }
  336.             (void) close(tfd);
  337.         }
  338.         if (link(tfname, cfname) < 0) {
  339.             printf("%s: cannot rename %s\n", name, cfname);
  340.             tfname[inchar]++;
  341.             cleanup();
  342.         }
  343.         unlink(tfname);
  344.         if (qflag)        /* just q things up */
  345.             exit(0);
  346.         if (!startdaemon(printer))
  347.             printf("jobs queued, but cannot start daemon.\n");
  348.         exit(0);
  349.     }
  350.     cleanup();
  351.     /* NOTREACHED */
  352. }
  353.  
  354. /*
  355.  * Create the file n and copy from file descriptor f.
  356.  */
  357. copy(f, n)
  358.     int f;
  359.     char n[];
  360. {
  361.     register int fd, i, nr, nc;
  362.     char buf[BUFSIZ];
  363.  
  364.     if (format == 'p')
  365.         card('T', title ? title : n);
  366.     for (i = 0; i < ncopies; i++)
  367.         card(format, &dfname[inchar-2]);
  368.     card('U', &dfname[inchar-2]);
  369.     card('N', n);
  370.     fd = nfile(dfname);
  371.     nr = nc = 0;
  372.     while ((i = read(f, buf, BUFSIZ)) > 0) {
  373.         if (write(fd, buf, i) != i) {
  374.             printf("%s: %s: temp file write error\n", name, n);
  375.             break;
  376.         }
  377.         nc += i;
  378.         if (nc >= BUFSIZ) {
  379.             nc -= BUFSIZ;
  380.             nr++;
  381.             if (MX > 0 && nr > MX) {
  382.                 printf("%s: %s: copy file is too large\n", name, n);
  383.                 break;
  384.             }
  385.         }
  386.     }
  387.     (void) close(fd);
  388.     if (nc==0 && nr==0) 
  389.         printf("%s: %s: empty input file\n", name, f ? n : "stdin");
  390.     else
  391.         nact++;
  392. }
  393.  
  394. /*
  395.  * Try and link the file to dfname. Return a pointer to the full
  396.  * path name if successful.
  397.  */
  398. char *
  399. linked(file)
  400.     register char *file;
  401. {
  402.     register char *cp;
  403.     static char buf[BUFSIZ];
  404.  
  405.     if (*file != '/') {
  406.         if (getwd(buf) == NULL)
  407.             return(NULL);
  408.         while (file[0] == '.') {
  409.             switch (file[1]) {
  410.             case '/':
  411.                 file += 2;
  412.                 continue;
  413.             case '.':
  414.                 if (file[2] == '/') {
  415.                     if ((cp = rindex(buf, '/')) != NULL)
  416.                         *cp = '\0';
  417.                     file += 3;
  418.                     continue;
  419.                 }
  420.             }
  421.             break;
  422.         }
  423.         strcat(buf, "/");
  424.         strcat(buf, file);
  425.         file = buf;
  426.     }
  427.     return(symlink(file, dfname) ? NULL : file);
  428. }
  429.  
  430. /*
  431.  * Put a line into the control file.
  432.  */
  433. card(c, p2)
  434.     register char c, *p2;
  435. {
  436.     char buf[BUFSIZ];
  437.     register char *p1 = buf;
  438.     register int len = 2;
  439.  
  440.     *p1++ = c;
  441.     while ((c = *p2++) != '\0') {
  442.         *p1++ = c;
  443.         len++;
  444.     }
  445.     *p1++ = '\n';
  446.     write(tfd, buf, len);
  447. }
  448.  
  449. /*
  450.  * Create a new file in the spool directory.
  451.  */
  452. nfile(n)
  453.     char *n;
  454. {
  455.     register f;
  456.     int oldumask = umask(0);        /* should block signals */
  457.  
  458.     f = creat(n, FILMOD);
  459.     (void) umask(oldumask);
  460.     if (f < 0) {
  461.         printf("%s: cannot create %s\n", name, n);
  462.         cleanup();
  463.     }
  464.     if (fchown(f, userid, -1) < 0) {
  465.         printf("%s: cannot chown %s\n", name, n);
  466.         cleanup();
  467.     }
  468.     if (++n[inchar] > 'z') {
  469.         if (++n[inchar-2] == 't') {
  470.             printf("too many files - break up the job\n");
  471.             cleanup();
  472.         }
  473.         n[inchar] = 'A';
  474.     } else if (n[inchar] == '[')
  475.         n[inchar] = 'a';
  476.     return(f);
  477. }
  478.  
  479. /*
  480.  * Cleanup after interrupts and errors.
  481.  */
  482. cleanup()
  483. {
  484.     register i;
  485.  
  486.     signal(SIGHUP, SIG_IGN);
  487.     signal(SIGINT, SIG_IGN);
  488.     signal(SIGQUIT, SIG_IGN);
  489.     signal(SIGTERM, SIG_IGN);
  490.     i = inchar;
  491.     if (tfname)
  492.         do
  493.             unlink(tfname);
  494.         while (tfname[i]-- != 'A');
  495.     if (cfname)
  496.         do
  497.             unlink(cfname);
  498.         while (cfname[i]-- != 'A');
  499.     if (dfname)
  500.         do {
  501.             do
  502.                 unlink(dfname);
  503.             while (dfname[i]-- != 'A');
  504.             dfname[i] = 'z';
  505.         } while (dfname[i-2]-- != 'd');
  506.     exit(1);
  507. }
  508.  
  509. /*
  510.  * Test to see if this is a printable file.
  511.  * Return -1 if it is not, 0 if its printable, and 1 if
  512.  * we should remove it after printing.
  513.  */
  514. test(file)
  515.     char *file;
  516. {
  517.     struct exec execb;
  518.     register int fd;
  519.     register char *cp;
  520.  
  521.     if (access(file, 4) < 0) {
  522.         printf("%s: cannot access %s\n", name, file);
  523.         return(-1);
  524.     }
  525.     if (stat(file, &statb) < 0) {
  526.         printf("%s: cannot stat %s\n", name, file);
  527.         return(-1);
  528.     }
  529.     if ((statb.st_mode & S_IFMT) == S_IFDIR) {
  530.         printf("%s: %s is a directory\n", name, file);
  531.         return(-1);
  532.     }
  533.     if (statb.st_size == 0) {
  534.         printf("%s: %s is an empty file\n", name, file);
  535.         return(-1);
  536.      }
  537.     if ((fd = open(file, O_RDONLY)) < 0) {
  538.         printf("%s: cannot open %s\n", name, file);
  539.         return(-1);
  540.     }
  541.     if (read(fd, &execb, sizeof(execb)) == sizeof(execb))
  542.         switch(execb.a_magic) {
  543.         case A_MAGIC1:
  544.         case A_MAGIC2:
  545.         case A_MAGIC3:
  546. #ifdef A_MAGIC4
  547.         case A_MAGIC4:
  548. #endif
  549.             printf("%s: %s is an executable program", name, file);
  550.             goto error1;
  551.  
  552.         case ARMAG:
  553.             printf("%s: %s is an archive file", name, file);
  554.             goto error1;
  555.         }
  556.     (void) close(fd);
  557.     if (rflag) {
  558.         if ((cp = rindex(file, '/')) == NULL) {
  559.             if (access(".", 2) == 0)
  560.                 return(1);
  561.         } else {
  562.             *cp = '\0';
  563.             fd = access(file, 2);
  564.             *cp = '/';
  565.             if (fd == 0)
  566.                 return(1);
  567.         }
  568.         printf("%s: %s: is not removable by you\n", name, file);
  569.     }
  570.     return(0);
  571.  
  572. error1:
  573.     printf(" and is unprintable\n");
  574.     (void) close(fd);
  575.     return(-1);
  576. }
  577.  
  578. /*
  579.  * itoa - integer to string conversion
  580.  */
  581. char *
  582. itoa(i)
  583.     register int i;
  584. {
  585.     static char b[10] = "########";
  586.     register char *p;
  587.  
  588.     p = &b[8];
  589.     do
  590.         *p-- = i%10 + '0';
  591.     while (i /= 10);
  592.     return(++p);
  593. }
  594.  
  595. /*
  596.  * Perform lookup for printer name or abbreviation --
  597.  */
  598. chkprinter(s)
  599.     char *s;
  600. {
  601.     int status;
  602.     char buf[BUFSIZ];
  603.     static char pbuf[BUFSIZ/2];
  604.     char *bp = pbuf;
  605.     extern char *pgetstr();
  606.  
  607.     if ((status = pgetent(buf, s)) < 0)
  608.         fatal("cannot open printer description file");
  609.     else if (status == 0)
  610.         fatal("%s: unknown printer", s);
  611.     if ((SD = pgetstr("sd", &bp)) == NULL)
  612.         SD = DEFSPOOL;
  613.     if ((LO = pgetstr("lo", &bp)) == NULL)
  614.         LO = DEFLOCK;
  615.     RG = pgetstr("rg", &bp);
  616.     if ((MX = pgetnum("mx")) < 0)
  617.         MX = DEFMX;
  618.     if ((MC = pgetnum("mc")) < 0)
  619.         MC = DEFMAXCOPIES;
  620.     if ((DU = pgetnum("du")) < 0)
  621.         DU = DEFUID;
  622.     SC = pgetflag("sc");
  623. }
  624.  
  625. /*
  626.  * Make the temp files.
  627.  */
  628. mktemps()
  629. {
  630.     register int c, len, fd, n;
  631.     register char *cp;
  632.     char buf[BUFSIZ];
  633.     char *mktemp();
  634.  
  635.     (void) sprintf(buf, "%s/.seq", SD);
  636.     if ((fd = open(buf, O_RDWR|O_CREAT, 0661)) < 0) {
  637.         printf("%s: cannot create %s\n", name, buf);
  638.         exit(1);
  639.     }
  640.     if (flock(fd, LOCK_EX)) {
  641.         printf("%s: cannot lock %s\n", name, buf);
  642.         exit(1);
  643.     }
  644.     n = 0;
  645.     if ((len = read(fd, buf, sizeof(buf))) > 0) {
  646.         for (cp = buf; len--; ) {
  647.             if (*cp < '0' || *cp > '9')
  648.                 break;
  649.             n = n * 10 + (*cp++ - '0');
  650.         }
  651.     }
  652.     len = strlen(SD) + strlen(host) + 8;
  653.     tfname = mktemp("tf", n, len);
  654.     cfname = mktemp("cf", n, len);
  655.     dfname = mktemp("df", n, len);
  656.     inchar = strlen(SD) + 3;
  657.     n = (n + 1) % 1000;
  658.     (void) lseek(fd, 0L, 0);
  659.     sprintf(buf, "%03d\n", n);
  660.     (void) write(fd, buf, strlen(buf));
  661.     (void) close(fd);    /* unlocks as well */
  662. }
  663.  
  664. /*
  665.  * Make a temp file name.
  666.  */
  667. char *
  668. mktemp(id, num, len)
  669.     char    *id;
  670.     int    num, len;
  671. {
  672.     register char *s;
  673.     extern char *malloc();
  674.  
  675.     if ((s = malloc(len)) == NULL)
  676.         fatal("out of memory");
  677.     (void) sprintf(s, "%s/%sA%03d%s", SD, id, num, host);
  678.     return(s);
  679. }
  680.  
  681. /*VARARGS1*/
  682. fatal(msg, a1, a2, a3)
  683.     char *msg;
  684. {
  685.     printf("%s: ", name);
  686.     printf(msg, a1, a2, a3);
  687.     putchar('\n');
  688.     exit(1);
  689. }
  690.